﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WebUI.Infrastructure;
using WebUI.Models;
using WebUI.Utils;
using Utils;
using DomainModel;
using System.Web.UI;
using System.Web.Security;
using WebUI.HtmlHelpers;
using WebUI.ActionFilter;

namespace WebUI.Controllers
{
    public class IndController : BaseController
    {
        ///////////////don't need Authorize here//////////////////
        public ActionResult Shot(int shotID)
        { 
            //check if valid input
            Shot shot = DataUtils.GetOne<Shot>(ConstUtils.SP_GetShotForDisplaying, new { ShotID = shotID });
            if (shot != null && shot.ShotID > 0)
            {
                return View(new IndShotViewModel(shot));
            }
            else
            {
                return View("Error404", new BaseViewModel());
            }
        }

        public ActionResult ShotOriginal(int shotID)
        {
            //check if valid input
            Shot shot = DataUtils.GetOne<Shot>(ConstUtils.SP_GetShotForDisplaying, new { ShotID = shotID });
            if (shot != null && shot.ShotID > 0)
            {
                return View(new IndShotOriginalViewModel(shot));
            }
            else
            {
                return View("Error404", new BaseViewModel());
            }
        }

        public ActionResult Shots(string userName, int? page)
        {
            //check if valid input
            Login login = DataUtils.GetLoginByName(userName);
            if (login != null && login.LoginID > 0)
            {
                return View(new IndShotsViewModel(userName, login.LoginID, page == null ? 1 : page.Value));
            }
            else
            {
                return View("Error404", new BaseViewModel());
            }
        }
        public ActionResult Resume(string userName)
        {
            //check if valid input
            Login login = DataUtils.GetLoginByName(userName);
            if (login != null && login.LoginID > 0)
            {
                return View(new IndResumeViewModel(userName, login.LoginID));
            }
            else
            {
                return View("Error404", new BaseViewModel());
            }
        }

        public ActionResult Tags(string userName, string tag, int? page)
        {
            //check if valid input
            Login login = DataUtils.GetLoginByName(userName);
            if (login != null && login.LoginID > 0)
            {
                return View(new IndTagsViewModel(userName, login.LoginID, tag, page == null ? 1 : page.Value));
            }
            else
            {
                return View("Error404", new BaseViewModel());
            }
        }

        ///////////////NEED Authorize//////////////////
        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult SavedJobs(int? page)
        {
            return View(new IndSavedJobViewModel(page == null ? 1 : page.Value));
        }

        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult SavedTalent(int? page)
        {
            return View(new IndSavedTalentViewModel(page == null ? 1 : page.Value));
        }

        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult DeleteAccount()
        {
            return View(new BaseViewModel());
        }
        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        public ActionResult Delete()
        {
            try
            {
                DataUtils.DeleteAccount(IdentityWithoutUserName.LoginID, IdentityWithoutUserName.AccountID, IdentityWithoutUserName.AccountType);
                CreateSessionMessageForSuccess("Your account has been deleted successfully");
                FormsAuthentication.SignOut();
                return Redirect("/");
            }
            catch
            {
                CreateSessionMessageForError("Sorry, internal error occurs. Please try it again");
                return RedirectToAction("DeleteAccount");
            }
        }

        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult SendEmailConfirmation()
        {
            IndLogin indLogin = DataUtils.GetIndLoginByID(IdentityWithoutUserName.LoginID);
            string newConfirmationKey = CommonUtilities.CreateGUIDKey();
            //update key in db first, 
            SqlUtilities.Execute(ConstUtils.SP_UpdateEmailConfirmationKey, new { LoginID = IdentityWithoutUserName.LoginID, Key = newConfirmationKey }, null, true);
            //then send email
            EmailUtils.Send(
                GlobalUtilities.GetInstance().Email_NoReply, 
                indLogin.Login.Email, 
                EmailTemplateType.SignUp,
                new string[]{
                    indLogin.Ind.FirstName + " " + indLogin.Ind.LastName,
                    indLogin.Login.Email,
                    AbsoluteUrlForEmailConfirmation(indLogin.Login.Email, newConfirmationKey)
                }, indLogin.Login.LoginID);
            return RedirectToAction("EditProfile");
        }

        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult EditProfile()
        {
            return View(new IndEditProfileViewModel());
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult EditProfile(IndEditProfileViewModel model)
        {
            if (ModelState.IsValid)
            {
                //update login and Ind
                //check username unique
                //check if username, email exists in db, although now we don't allow user to change email, but we can keep code here
                int checkResult = SqlUtilities.Query<int>(ConstUtils.SP_CheckUserNameAndEmail, new { Email = model.Login.Email, UserName = model.Login.UserName, LoginID = IdentityWithoutUserName.LoginID }).Single();
                //passed, insert into db
                if (checkResult == 0)
                {
                    try
                    {
                        SqlUtilities.Execute(ConstUtils.SP_UpdateLoginAndInd, new
                        {
                            LoginID = IdentityWithoutUserName.LoginID,
                            UserName = model.Login.UserName,
                            FirstName = model.Ind.FirstName,
                            LastName = model.Ind.LastName,
                            Title = model.Ind.Title,
                            Location = model.Ind.Location,
                            PersonalUrl = model.Ind.PersonalUrl,
                            Twitter = model.Ind.Twitter,
                            Bio = model.Ind.Bio,
                            AvailableForHire = model.Ind.AvailableForHire
                        }, null, true);
                        base.CreateSessionMessageForSuccess("Your change has been updated");
                    }
                    catch
                    {
                        base.CreateSessionMessageForError("Sorry, internal error occurred. Please try it again.");
                    }
                }
                else if (checkResult == 1)
                {
                    ModelState.AddModelError("Login.Email", "This Email has been registered in our system.");
                }
                else if (checkResult == 2)
                {
                    ModelState.AddModelError("Login.UserName", "This User name has been taken in our system.");
                }
                else
                {
                    ModelState.AddModelError("Login.Email", "This Email has been registered in our system.");
                    ModelState.AddModelError("Login.UserName", "This User name has been taken in our system.");
                }

                
                return View(model);
            }
            else
            {
                return View(model);
            }
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        public JsonResult EditAvatar(IndEditProfileViewModel model)
        {
            //check Avatar, validate file type, size etc
            if (ModelState.IsValid)
            {
                //upload file to disk, create differnt size thumbnail, extract image file info: width, height, insert into db 
                //update AvatarUrl in model
                UploadResult result = ImageUtils.UploadAvatar(model.Avatar, GetWebProjectPhysicalPath(), AvatarType.IndAvatar, IdentityWithoutUserName.AccountID);
                if (result.Result  == UploadResultEnum.Success)
                {
                    return Json(
                        JsonResultUploadFileModelHelper.ForSuccessWithFilePathAndSummaryMessage(
                            Url.StaticFile(ImageUtils.GetAvatarRelativeUrl(AvatarType.IndAvatar, IdentityWithoutUserName.AccountID, 
                                AvatarSizeEnum.Avatar_80x80, ImageUtils.GetImageFileExtension(model.Avatar))), 
                            "Your Avatar has been updated"
                        )
                    );
                }
                else{
                    string message = ViewModelUtils.GetUploadErrorMessage(result.Result);
                    return Json(JsonResultUploadFileModelHelper.ForError(message));
                }
            }
            else
            {
                return Json(JsonResultUploadFileModelHelper.ForError("Some error occurs, please try it again."));
            }
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        [ValidateInput(false)]
        public JsonResult AddSkill(Skill skill)
        {
            if (ModelState.IsValid)
            {
                //check ind skill count, at most 10
                int count = DataUtils.GetOne<int>(ConstUtils.SP_GetIndSkillCount, new { IndID = IdentityWithoutUserName.AccountID });
                if (count < 10)
                {

                    string normalizedTag = skill.Name.ToLower();
                    //try add into db
                    int skillID = DataUtils.InsertSkill(IdentityWithoutUserName.AccountID, normalizedTag);
                    if (skillID < 0)
                    {
                        return Json(new { Success = 0, Message = "Internal error occurs, please try it again." });
                    }
                    else
                    {
                        //if skillID == 0, means dups, don't add one more in UI
                        return Json(new { Success = 1, Message = "", SkillID = skillID, Name = normalizedTag });
                    }
                }
                else
                {
                    return Json(new { Success = 0, Message = "You already added 10 skills." });
                }

            }
            else
            {
                return Json(new { Success = 0, Message = GetFirstModelStateErrorMessage(ModelState) }); //this for ajax form
            }
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        public JsonResult DeleteSkill(int skillID)
        {
            try
            {
                SqlUtilities.Execute(ConstUtils.SP_DeleteSkill, new { IndID = IdentityWithoutUserName.AccountID, SkillID = skillID }, null, true);
                return Json(new { Success = 1}); //normal ajax, don't need return text/html
            }
            catch
            {
                return Json(new { Success = 0});
            }

        }

        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult EditResume()
        {
            return View(new IndEditResumeViewModel());
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult EditResume(IndEditResumeViewModel model)
        {
            if (ModelState.IsValid)
            {
                //save resume to db
                try
                {
                    SqlUtilities.Execute(ConstUtils.SP_UpdateIndResume, new { IndID = IdentityWithoutUserName.AccountID, Resume = model.Resume.ToRichHtml() }, null, true);
                    base.CreateSessionMessageForSuccess("Your resume has been updated");
                }
                catch
                {
                    ModelState.AddModelError("Resume", "Internal error occurs. Please try it again.");
                }
                
            }
            return View(model);
        }

        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult EditPassword()
        {
            return View(new IndEditPasswordViewModel());
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult EditPassword(IndEditPasswordViewModel model)
        {
            if (ModelState.IsValid)
            {
                //save new password to db
                try
                {
                    string goodHash = string.Empty;
                    Login login = DataUtils.GetLoginByID(IdentityWithoutUserName.LoginID);
                    if (login != null)
                    {
                        goodHash = login.PasswordHash;
                    }
                    if (PasswordHash.ValidatePassword(model.OldPassword, goodHash))
                    {
                        SqlUtilities.Execute(ConstUtils.SP_UpdatePassword,
                            new
                            {
                                LoginID = IdentityWithoutUserName.LoginID,
                                NewPasswordHash = PasswordHash.CreateHash(model.NewPassword)
                            },
                            null, true);
                        base.CreateSessionMessageForSuccess("Your password has been updated");
                    }
                    else
                    {
                        ModelState.AddModelError("OldPassword", "Old password is incorrect");
                    }
                    
                }
                catch
                {
                    ModelState.AddModelError("", "Internal error occurs. Please try it again.");
                }

            }
            return View(model);
        }

        [HttpGet]
        [NoCache]
        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult UploadShot()
        {
            return View(new IndUploadShotViewModel());
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult UploadShot(IndUploadShotViewModel model)
        {
            if (ModelState.IsValid)
            {
                //upload file to disk, create differnt size thumbnail, extract image file info: width, height, insert into db 
                //update AvatarUrl in model
                UploadResult result = ImageUtils.UploadShot(model.Shot, GetWebProjectPhysicalPath(), IdentityWithoutUserName.AccountID, model.Title, model.Description);
                if (result.Result == UploadResultEnum.Success)
                {
                    CreateSessionForPreviousStepSuccess();
                    CreateSessionMessageForSuccess("Upload shot successfully");
                    return RedirectToAction("AddShotTag", new { ShotID = result.NewID });
                }
                else
                {
                    string message = ViewModelUtils.GetUploadErrorMessage(result.Result);
                    //return Json(new { Success = 0, Message = message });
                    CreateSessionMessageForError(message);
                    return View(model);
                }
            }
            else
            {

                return View(model);
            }
        }

        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult AddShotTag(int shotID)
        {
            if (SessionExistsForPreviousStepSuccess())
            {
                var shot = DataUtils.GetOne<Shot>(ConstUtils.SP_GetShot, new { IndID = IdentityWithoutUserName.AccountID, ShotID = shotID });
                if (shot.ShotID > 0)
                {
                    return View(new IndAddShotTagViewModel(shot));
                }
                else
                {
                    return RedirectToAction("Shots", new { UserName = IdentityWithUserName.UserName });
                }
            }
            else
            {
                return RedirectToAction("EditShot", new { ShotID = shotID });
            }
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        [ValidateInput(false)]
        public JsonResult AddShotTag(int shotID, STag stag)
        {
            if (ModelState.IsValid)
            {
                //check shot tag count
                int count = DataUtils.GetOne<int>(ConstUtils.SP_GetShotTagCount, new { IndID = IdentityWithoutUserName.AccountID, ShotID = shotID });
                if (count < 10)
                {

                    string normalizedTag = stag.Name.ToLower();
                    //try add into db
                    int stagID = DataUtils.InsertShotTag(IdentityWithoutUserName.AccountID, shotID, normalizedTag);
                    if (stagID < 0)
                    {
                        return Json(new { Success = 0, Message = "Internal error occurs, please try it again." });
                    }
                    else
                    {
                        //if skillID == 0, means dups, don't add one more in UI
                        return Json(new { Success = 1, Message = "", STagID = stagID, Name = normalizedTag });
                    }
                }
                else
                {
                    return Json(new { Success = 0, Message = "You already added 10 tags." });
                }

            }
            else
            {
                return Json(new { Success = 0, Message = GetFirstModelStateErrorMessage(ModelState) }); //this for ajax form
            }
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        public JsonResult DeleteShotTag(int shotID, int stagID)
        {
            try
            {
                SqlUtilities.Execute(ConstUtils.SP_DeleteShotTag, new { IndID = IdentityWithoutUserName.AccountID, ShotID = shotID, STagID = stagID }, null, true);
                return Json(new { Success = 1 }); //normal ajax, don't need return text/html
            }
            catch
            {
                return Json(new { Success = 0 });
            }

        }

        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult EditShot(int shotID)
        {
            var shot = DataUtils.GetOne<Shot>(ConstUtils.SP_GetShot, new { IndID = IdentityWithoutUserName.AccountID, ShotID = shotID });
            if (shot.ShotID > 0)
            {
                return View(new IndEditShotViewModel(shot));
            }
            else
            {
                //return RedirectToAction("Shots", new { UserName = IdentityWithUserName.UserName });
                return View("Error404", new BaseViewModel());
            }
        }

        [Authorize(Roles = RoleNames.Individual)]
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult EditShot(IndEditShotViewModel model)
        {
            if (ModelState.IsValid)
            {
                //update shot
                DataUtils.UpdateShot(IdentityWithoutUserName.AccountID, model.ShotID, model.Title, model.Description);
                //for dynParams, need create view model
                //for no dynParams, don't need view model, just return View(model)
                CreateSessionMessageForSuccess("Your change has been updated");
                var shot = DataUtils.GetOne<Shot>(ConstUtils.SP_GetShot, new { IndID = IdentityWithoutUserName.AccountID, ShotID = model.ShotID });
                return View(new IndEditShotViewModel(shot));
            }
            else
            {
                return View(model);
            }
        }

        [Authorize(Roles = RoleNames.Individual)]
        public ActionResult DeleteShot(int shotID)
        {
            try
            {
                DataUtils.DeleteShot(IdentityWithoutUserName.AccountID, shotID);
                CreateSessionMessageForSuccess("The selected shot has been deleted");
            }
            catch
            {
                CreateSessionMessageForError("Sorry, internal error occurs. Please try it again");
            }
            return RedirectToAction("Shots", new { UserName = IdentityWithUserName.UserName });
        }
    }
}
